<?php
/**
 * 注意：本内容仅限于博也公司内部传阅,禁止外泄以及用于其他的商业目的
 * @author    hebidu<346551990@qq.com>
 * @copyright 2018 www.itboye.com Boye Inc. All rights reserved.
 * @link      http://www.itboye.com/
 * @license   http://www.opensource.org/licenses/mit-license.php MIT License
 * Revision History Version
 ********1.0.0********************
 * file created @ 2018-03-23 16:46
 *********************************
 ********1.0.1********************
 *
 *********************************
 */

namespace by\component\pahys\api;


use by\component\pahys\context\BaseContext;
use by\component\pahys\helper\SignHelper;
use by\component\pahys\helper\TripleDesHelper;
use by\infrastructure\base\CallResult;
use by\infrastructure\helper\CallResultHelper;
use Curl\Curl;

/**
 * Class BaseApi
 * @property BaseContext $context
 * @package by\component\pahys\api
 */
abstract class BaseApi
{

    protected $context;

    public function __construct(BaseContext $context)
    {
        $this->context = $context;
    }

    abstract function getVersion();

    /**
     * @return string
     */
    abstract function getApiGroup();

    /**
     * @return string
     */
    abstract function getApiName();

    private function strToArray($data)
    {
        $tmp = [];
        $parse = explode('&', $data);
        foreach ($parse as $val) {
            $kv = explode("=", $val);
            if (count($kv) == 2) {
                $tmp[$kv[0]] = $kv[1];
            }
        }
        return $tmp;
    }

    /**
     * 包装请求同时进行验证
     * @param $url
     * @param array $bussParams
     * @return CallResult
     * @throws \ErrorException
     */
    public function wrapPostAndVerify($url, $bussParams = [])
    {
        $result = $this->post($url, $bussParams);
        if ($result->isSuccess()) {
            $data = $result->getData();
            $data = json_decode($data, JSON_OBJECT_AS_ARRAY);
            if ($data['code'] == 0) {
                $obj = $this->strToArray($data['object']);
                $d = $obj['d'];
                $s = $obj['s'];
                $h = $obj['h'];
                $key = $this->context->getKey();
                $hmac = SignHelper::signHmac($d . $s, $key);

                if ($hmac != $h) {
                    return CallResultHelper::fail('[PAHYS-SIGN]签名验证失败', $obj);
                }

                $d = $this->decrypt($d, $key);
                if ($d === false) {
                    return CallResultHelper::fail('[PAHYS-DECR] 3DES解密失败');
                }

                $parseD = $this->strToArray($d);

                return CallResultHelper::success($parseD);
            } else {
                $msg = $data['message'] . '|' . $data['tips'];
                return CallResultHelper::fail($msg, $data, $data['code']);
            }
        }
    }

    /**
     * 请求
     * @param $url
     * @param array $bussParams 业务参数
     * @return CallResult
     * @throws \ErrorException
     */
    public function post($url, $bussParams = [])
    {
        $curl = new Curl();
        $curl->setHeader("content-type", "application/x-www-form-urlencoded");
        $curl->setHeader("charset", "utf-8");

        $curl->setOpt(CURLOPT_SSL_VERIFYPEER, false);
        $curl->setOpt(CURLOPT_SSL_VERIFYHOST, false);
        $resp = $curl->post($url, $bussParams, true);
        $curl->close();
        if ($curl->error) {
            return CallResultHelper::fail($curl->errorMessage);
        }
        return CallResultHelper::success($resp);
    }

    public function decrypt($d, $key)
    {
        $desKey = md5($key);
        $desKey = $desKey . substr($desKey, 0, 16);
        $desKey = pack("H48", $desKey);
        $iv = pack("H16", "0000000000000000");

        $decrypt = TripleDesHelper::decrypt($d, $desKey, $iv);
        return $decrypt;
    }

    public function encrypt($params, $key)
    {
        ksort($params);
        $str = '';
        foreach ($params as $keyParam => $keyValue) {
            if (!empty($str)) {
                $str .= '&';
            }
            $str .= $keyParam . '=' . urlencode($keyValue);
        }

        $desKey = md5($key);
        $desKey = $desKey . substr($desKey, 0, 16);
        $desKey = pack("H48", $desKey);
        $iv = pack("H16", "0000000000000000");
//        $iv = '';
//        $str = '__o_s=c88399a45eb54ecc872972400d880200#OPENAPI_DUBBO_DEV&__o_v=0.1.0&arg1={"apiId":1,"apiName":"ApiInfo","dateTime":"2016-12-02 12:22:23","serialNum":2}&__o_r=297335.97035396';
        $encryptStr = TripleDesHelper::encrypt($str, $desKey, $iv);
//        echo $encryptStr . "\n";
//        $encryptStr = TripleDesHelper::encryptOld($str, $desKey, $iv);
//        echo 'old=' . $encryptStr;

        return $encryptStr;
    }
}